﻿namespace OutLook.Model.Domains
{
    using System;
    using System.Collections.Generic;
    using System.Runtime.Serialization;
    using OutLook.Model.Infrastructure;

    /// <summary>
    /// Load information object
    /// </summary>
    [DataContract]
    public class LoadData : IEquatable<LoadData>, IDisposable, IValidatable
    {
        #region Constructors

        /// <summary>
        /// TODO:Nastya
        /// </summary>
        private LoadData() : this(string.Empty, new ChargeRowToLoad[0], new LossRowToLoad[0], string.Empty, 0.0d) { }

        /// <summary>
        /// TODO:Nastya
        /// </summary>
        /// <param name="title">TODO:Nastya</param>
        /// <param name="chargeToLoad">TODO:Nastya</param>
        /// <param name="lossToLoad">TODO:Nastya</param>
        /// <param name="typeOfWeight">TODO:Nastya</param>
        /// <param name="production">TODO:Nastya</param>
        private LoadData(string title, IEnumerable<ChargeRowToLoad> chargeToLoad,
                     IEnumerable<LossRowToLoad> lossToLoad, string typeOfWeight, double production)
        {
            Title = title;
            m_ChargeToLoad.Clear();
            m_ChargeToLoad.AddRange(chargeToLoad);
            m_LossToLoad.Clear();
            m_LossToLoad.AddRange(lossToLoad);
            TypeOfWeight = typeOfWeight;
            Production = production;
        }

        /// <summary>
        /// TODO:Nastya
        /// </summary>
        /// <param name="title">TODO:Nastya</param>
        /// <param name="chargeToLoad">TODO:Nastya</param>
        /// <param name="typeOfWeight">TODO:Nastya</param>
        /// <param name="production">TODO:Nastya</param>
        private LoadData(string title, IEnumerable<ChargeRowToLoad> chargeToLoad, string typeOfWeight, double production) :
            this(title, chargeToLoad, new List<LossRowToLoad>(), typeOfWeight, production) { }

        #endregion       

        #region Properties

        /// <summary>
        /// Title of load
        /// </summary>
        [DataMember(Order = 1)]
        public string Title
        {
            get { return m_Title; }
            set { m_Title = value; }
        }

        /// <summary>
        /// Charge to load
        /// </summary>
        [DataMember(Order = 2)]
        public List<ChargeRowToLoad> ChargeToLoad
        {
            get { return m_ChargeToLoad; }
            private set { m_ChargeToLoad = value; }
        }

        /// <summary>
        /// Loss to load
        /// </summary>
        [DataMember(Order = 3)]
        public List<LossRowToLoad> LossToLoad
        {
            get { return m_LossToLoad; }
            private set { m_LossToLoad = value; }
        }

        /// <summary>
        /// Property indicates, what type of weight is in load (ton or kg/ton)
        /// </summary>
        [DataMember(Order = 4)]
        public string TypeOfWeight
        {
            get { return m_TypeOfWeight; }
            set { m_TypeOfWeight = value; }
        }

        /// <summary>
        /// Production for load, which has type of weight in kg/ton
        /// </summary>
        [DataMember(Order = 5)]
        public double Production
        {
            get { return m_Production; }
            set { m_Production = value; }
        }

        #endregion

        #region Factory Method

        /// <summary>
        /// TODO:Nastya
        /// </summary>
        /// <returns>TODO:Nastya</returns>
        public static LoadData Create()
        {
            return new LoadData();
        }

        /// <summary>
        /// TODO:Nastya
        /// </summary>
        /// <param name="title">TODO:Nastya</param>
        /// <param name="chargeToLoad">TODO:Nastya</param>
        /// <param name="typeOfWeight">TODO:Nastya</param>
        /// <param name="production">TODO:Nastya</param>
        /// <returns>TODO:Nastya</returns>
        public static LoadData Create(string title, IEnumerable<ChargeRowToLoad> chargeToLoad, string typeOfWeight, double production)
        {
            return LoadData.Create(title, chargeToLoad, new List<LossRowToLoad>(), typeOfWeight, production);
        }

        /// <summary>
        /// TODO:Nastya
        /// </summary>
        /// <param name="loadData">TODO:Nastya</param>
        /// <returns>TODO:Nastya</returns>
        public static LoadData Create(LoadData loadData)
        {
            return LoadData.Create(loadData.Title, loadData.ChargeToLoad, loadData.LossToLoad, loadData.TypeOfWeight, loadData.Production);
        }

        /// <summary>
        /// TODO:Nastya
        /// </summary>
        /// <param name="title">TODO:Nastya</param>
        /// <param name="chargeToLoad">TODO:Nastya</param>
        /// <param name="lossToLoad">TODO:Nastya</param>
        /// <param name="typeOfWeight">TODO:Nastya</param>
        /// <param name="production">TODO:Nastya</param>
        /// <returns>TODO:Nastya</returns>
        public static LoadData Create(string title, IEnumerable<ChargeRowToLoad> chargeToLoad,
                                  IEnumerable<LossRowToLoad> lossToLoad, string typeOfWeight, double production)
        {
            if (chargeToLoad == null || lossToLoad == null)
                return null;

            return new LoadData(title, chargeToLoad, lossToLoad, typeOfWeight, production);
        }
        #endregion

        #region IEquatable<Load> Implementation

        /// <summary>
        /// Compares current LoadData with another one
        /// </summary>
        /// <param name="other">Another LoadData</param>
        /// <returns>True - If current LoadData and another one are equal, otherwise -False</returns>
        public bool Equals(LoadData other)
        {
            if (other == null)
                return false;

            if (!Title.Equals(other.Title) || !TypeOfWeight.Equals(other.TypeOfWeight) || Production != other.Production)
                return false;

            if (ChargeToLoad.Count != other.ChargeToLoad.Count || LossToLoad.Count != other.LossToLoad.Count)
                return false;

            bool result = true;
            for (int i = 0; i < ChargeToLoad.Count; i++)
            {
                if (!ChargeToLoad[i].Equals(other.ChargeToLoad[i]))
                {
                    result = false;
                    break;
                }
            }

            for (int i = 0; i < LossToLoad.Count; i++)
            {
                if (!result || !LossToLoad[i].Equals(other.LossToLoad[i]))
                {
                    result = false;
                    break;
                }
            }

            return result;
        }

        #endregion

        #region IDisposable Implementation

        /// <summary>
        /// Releazes resources
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Releazes managed and unmanaged resources
        /// </summary>
        /// <param name="managedDispose">TODO: Yuliya</param>
        private void Dispose(bool managedDispose)
        {
            if (m_Dispose)
                return;

            if (managedDispose)
            {
                ///TODO: dispose managed
            }

           m_ChargeToLoad.Clear();
           m_LossToLoad.Clear();

            m_Dispose = true;
        }

        #endregion

        #region IValidatable Implementation

        /// <summary>
        /// Validates Load Data
        /// </summary>
        /// <returns>True - if current Load Data is valid, otherwise - false</returns>
        public bool Validate()
        {
            ///TODO:Load Data VALIDATION 
            if (string.IsNullOrWhiteSpace(m_Title) || string.IsNullOrEmpty(m_Title))
                return false;

            if (m_ChargeToLoad.Count == 0)
                return false;

            return true;
        }

        #endregion

        #region Finalize

        /// <summary>
        /// Finalizer for Load Data
        /// </summary>
        ~LoadData()
        {
            Dispose(false);
        }
        #endregion

        #region Private Fields

        private string m_Title = default(string);
        ///TODO:Спросить за композицию(readonly) и datacontract
        private List<ChargeRowToLoad> m_ChargeToLoad = new List<ChargeRowToLoad>();
        private List<LossRowToLoad> m_LossToLoad = new List<LossRowToLoad>();
        private string m_TypeOfWeight = default(string);
        private double m_Production = default(double);
        private bool m_Dispose = false;

        #endregion
    }
}
